package com.raptor.mongodb.spring;


import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.raptor.mongodb.api.MongodbRepositoryApi;
import com.raptor.mongodb.exception.MongoException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.util.StringUtils;

import java.util.List;

@Repository
public class MongoRepository<T> implements MongodbRepositoryApi<T> {


    private static Logger log = LoggerFactory.getLogger(MongoRepository.class);


    /**
     * 保存
     *
     * @param collectionName
     * @param t
     * @return
     * @throws MongoException
     */
    @Override
    public boolean save(String instance, String collectionName, T t) throws MongoException {
        if (t == null || StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(instance)) {
            throw new MongoException("illeagle parameter");
        }
        MongoTemplate mongoTemplate = (MongoTemplate) InnerSpringContextUtil.getBean(instance);
        try {
            T response = mongoTemplate.save(t, collectionName);
            if (response == null) {
                return false;
            }
            return true;
        } catch (Exception e) {
            log.error("", e);
            throw new MongoException(e.getMessage());
        }
    }

    /**
     * 判断是否存在
     */
    @Override
    public boolean exits(String instance, String collectionName, Class<T> clazz, Query query) throws MongoException {

        if (query == null || clazz == null || StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(instance)) {
            throw new MongoException("illeagle parameter");
        }
        MongoTemplate mongoTemplate = (MongoTemplate) InnerSpringContextUtil.getBean(instance);
        return mongoTemplate.exists(query, clazz, collectionName);
    }


    /**
     * 删除
     *
     * @param collectionName
     * @param query
     * @return
     */
    @Override
    public long remove(String instance, String collectionName, Query query) throws MongoException {
        if (query == null || StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(instance)) {
            throw new MongoException("illeagle parameter");
        }
        MongoTemplate mongoTemplate = (MongoTemplate) InnerSpringContextUtil.getBean(instance);
        DeleteResult result = mongoTemplate.remove(query, collectionName);
        return result == null ? 0 : result.getDeletedCount();
    }

    @Override
    public List<T> list(String instance, String collectionName, Query query, Class<T> clazz) throws MongoException {
        if (clazz == null || query == null || StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(instance)) {
            throw new MongoException("illeagle parameter");
        }
        MongoTemplate mongoTemplate = (MongoTemplate) InnerSpringContextUtil.getBean(instance);
        return mongoTemplate.find(query, clazz, collectionName);
    }


    @Override
    public long updateMulti(String instance, String collectionName, Update update, Query query, Class<T> clazz) throws MongoException {
        if (update == null || clazz == null || query == null || StringUtils.isEmpty(collectionName) || StringUtils.isEmpty(instance)) {
            throw new MongoException("illeagle parameter");
        }
        MongoTemplate mongoTemplate = (MongoTemplate) InnerSpringContextUtil.getBean(instance);
        UpdateResult updateResult = mongoTemplate.updateMulti(query, update, clazz, collectionName);
        return updateResult == null ? 0 : updateResult.getModifiedCount();
    }

    @Component("mongodbcontext")
    static class InnerSpringContextUtil implements ApplicationContextAware {


        private static ApplicationContext applicationContext; //Spring应用上下文环境


        @Override
        public void setApplicationContext(ApplicationContext applicationContext)
                throws BeansException {
            InnerSpringContextUtil.applicationContext = applicationContext;
        }


        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }


        public static Object getBean(String name) throws BeansException {
            return applicationContext.getBean(name);
        }


        public static Object getBean(Class classType) throws BeansException {
            return applicationContext.getBean(classType);
        }

        public static Object getBean(String name, Class requiredType)
                throws BeansException {
            return applicationContext.getBean(name, requiredType);
        }


        public static boolean containsBean(String name) {
            return applicationContext.containsBean(name);
        }


        public static boolean isSingleton(String name)
                throws NoSuchBeanDefinitionException {
            return applicationContext.isSingleton(name);
        }

        public static Class getType(String name)
                throws NoSuchBeanDefinitionException {
            return applicationContext.getType(name);
        }


        public static String[] getAliases(String name)
                throws NoSuchBeanDefinitionException {
            return applicationContext.getAliases(name);
        }
    }


}
